# -*- coding: binary -*-

module Msf
  module Exploit::Remote::SMB::Server
    module Share
      module Command
        module ReadAndx

          # Handles an SMB_COM_READ_ANDX command, used by the client to read data from a
          # file.
          #
          # @param c [Socket] The client sending the request.
          # @param buff [String] The data including the client request.
          # @return [Integer] The number of bytes returned to the client as response.
          def smb_cmd_read_andx(c, buff)
            pkt = CONST::SMB_READ_PKT.make_struct
            pkt.from_s(buff)

            offset = pkt['Payload'].v['Offset']
            length = pkt['Payload'].v['MaxCountLow']

            contents = get_file_contents(client: c)

            send_read_andx_res(c, {
              data_len_low: length,
              byte_count: length,
              data: contents[offset, length]
            })
          end

          # Builds and sends an SMB_COM_NT_CREATE_ANDX response.
          #
          # @param c [Socket] The client to answer.
          # @param opts [Hash{Symbol => <Integer, String>}] Response custom values.
          # @option opts [Integer] :data_len_low The length of the file data sent back.
          # @option opts [Integer] :byte_count The length of the file data sent back.
          # @option opts [String] :data The bytes read from the file.
          # @return [Integer] The number of bytes returned to the client as response.
          def send_read_andx_res(c, opts = {})
            data_len_low = opts[:data_len_low] || 0
            byte_count = opts[:byte_count] || 0
            data = opts[:data] || ''

            pkt = CONST::SMB_READ_RES_PKT.make_struct
            smb_set_defaults(c, pkt)

            pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_READ_ANDX
            pkt['Payload']['SMB'].v['Flags1'] = FLAGS
            pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
            pkt['Payload']['SMB'].v['WordCount'] = CONST::SMB_READ_ANDX_RES_WORD_COUNT
            pkt['Payload'].v['AndX'] = CONST::SMB_COM_NO_ANDX_COMMAND
            pkt['Payload'].v['Remaining'] = 0xffff
            pkt['Payload'].v['DataLenLow'] = data_len_low
            pkt['Payload'].v['DataOffset'] = CONST::SMB_READ_RES_HDR_PKT_LENGTH
            pkt['Payload'].v['DataLenHigh'] = 0
            pkt['Payload'].v['Reserved3'] = 0
            pkt['Payload'].v['Reserved4'] = 0x0a
            pkt['Payload'].v['ByteCount'] = byte_count
            pkt['Payload'].v['Payload'] = data
            c.put(pkt.to_s)
          end
        end
      end
    end
  end
end
